import { Inject, Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { RegisterUserDto } from './dto/register-user.dto';
import { CreateTokenDto } from './dto/create-token.dto'
import { validPhone, validEmail } from '../common/validate'
import { JwtService } from '@nestjs/jwt'
import { InjectRepository, InjectEntityManager} from '@nestjs/typeorm'
import { instanceToPlain, plainToInstance } from 'class-transformer'
import { genSalt, hash, compare, genSaltSync, hashSync } from 'bcryptjs'
import { User } from './entities/user.entity';
import { Repository, getRepository, Like, EntityManager, getConnection} from 'typeorm';
import { Tags } from './entities/tags.entity';
import { RedisClientType } from 'redis';
import { audit } from 'rxjs';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User) 
    private readonly user:Repository<User>,//依赖注入
    @InjectRepository(Tags) 
    private readonly tags:Repository<Tags>, //依赖注入
    @InjectEntityManager()
    private readonly userManager: EntityManager,
    private readonly jwtService: JwtService,
    @Inject('REDIS_CLIENT')
    private redisClient: RedisClientType
  ){}

  async addTags(params:{tags:string[],userId:number}){
    const userInfo = await this.user.findOne({where:{id:params.userId}});
    
    const tagList:Tags[] = [];
    for(let i = 0;i < params.tags.length;i++){
       const T = new Tags;
       T.name = params.tags[i];
       await this.tags.save(T);
       tagList.push(T);
    }
    userInfo.tags = tagList;
    this.user.save(userInfo);
    return true
  }

  async getTagsByUserId(userId:number){

    // 获取所有值
    // const value = await this.redisClient.keys('*');
    // console.log(value);
 
    // 设置值
    // const setvalue = await this.redisClient.set('demo', '11111');
 
    // 获取值
    // const getvalue = await this.redisClient.get('demo');
 
    // 删除值 1代表成功 0代表没有
    // const delvalue = await this.redisClient.del('demo');
 
    // 定时设置值 10s
    // const setTimevalue = await this.redisClient.set('demo', '11111', { EX: 10 })

    await this.redisClient.set("songtao.xiangs","testRedis",{ EX: 10000 });
    console.log(await this.redisClient.get("songtao.xiangs"));
    
    let key = 'userTags_' + userId;

    let userTagList = await this.redisClient.get(key);
    console.log("userTagList:"+userTagList);
    if(userTagList != null){
      console.log("redis缓存:"+userTagList.toString());
      return JSON.parse(userTagList);
    }else{
      const userEntity = await this.user
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.tags', 'tag')
      .where('user.id = :id', { id: userId })
      .getMany();
      console.log(userEntity[0].tags);
      let res = await this.redisClient.set(key,JSON.stringify(userEntity[0].tags),{ EX: 10000 });
      console.log("redis缓存成功！"+res);
      return ('userTags_' + userId+":redis缓存成功!")
    }

  }

  create(createUserDto: CreateUserDto) {
    const data = new User();
    data.name = createUserDto.name;
    data.desc = createUserDto.desc;
    return this.user.save(data);
  }


  /**
   * 登录
   * account 有可能是 帐号/手机/邮箱
   */
  async login(account: string, password: string) {
    let user = null
    if (validEmail(account)) {
      // 邮箱
      user = await this.user.findOne({ where: { email: account } })
    } else {
      // 帐号
      user = await this.findOneByName(account)
    }
    if (!user) return {code:200,message:'帐号或密码错误'}

    // 生成 token
    const data = this.genToken({ id: user.id,name:user.name })

    if(user.name == "小满"){
      if(user.password == password){
        return {status:200,message:'登录成功!',token:data}
      }else{
        return {status:200,message:'密码错误!'}
      }
    }else{
      const checkPassword = await compare(password, user.password)
      if (!checkPassword) return {code:200,message:'帐号或密码错误'}
      // if (user.status === 0) return {code:200,message:'您已被禁用，如需正常使用请联系管理员'}
      return {
        token:data,
        message:"登录成功",
        status: 200
      }
    }
  }

  async findOneByName(name: string): Promise<User> {
    return await this.user.findOne({ where: { name } })
  }

  /**
   * 生成 token 与 刷新 token
   * @param payload
   * @returns
   */
  genToken(payload: { id:string,name:string }): CreateTokenDto {
    const accessToken = `Bearer ${this.jwtService.sign(payload,{secret:process.env.SECRET,expiresIn: '1h'})}`
    const refreshToken = this.jwtService.sign(payload,{secret:process.env.SECRET,expiresIn: '2h' })
    return { accessToken, refreshToken }
  }

  /**
   * 生成刷新 token
   */
  refreshToken(payload: { id:string,name:string }): string {
    return this.jwtService.sign(payload,{secret:process.env.SECRET,expiresIn: '2h' })
  }

  /** 校验 token */
  verifyToken(token: string): string {
    try {
      if (!token) return null
      const id = this.jwtService.verify(token.replace('Bearer ', ''),{secret:process.env.SECRET})
      return id
    } catch (error) {
      return null
    }
  }

   /** 
    * 注册 
    */
   async register(dto: RegisterUserDto) {
    if (dto.password !== dto.confirmPassword)
      return {code:200, message:'两次输入密码不一致，请重试'}
    // 防止重复创建 start
    if (await this.findOneByName(dto.name))
      return {code:200, message:'帐号已存在，请调整后重新注册！'}
    if (await this.user.findOne({ where: { email: dto.email } }))
      return {code:200, message:'当前邮箱已存在，请调整后重新注册！'}
    // 防止重复创建 end
    const salt = await genSalt()
    dto.password = await hash(dto.password, salt);//密码加盐加密
    // plainToInstance  忽略转换 @Exclude 装饰器
    const user = plainToInstance(User, { salt, ...dto }, { ignoreDecorators: true })
    const result = await this.userManager.transaction(async (transactionalEntityManager) => {
      return await transactionalEntityManager.save<User>(user)
    })
    return {message:"注册成功！",data:instanceToPlain(result)}
  }


  async findAll(query:{keyWord:string,page:number,pageSize:number}) {
    const data = await this.user.find({
      relations:['tags'],
      where:{
        name:Like(`%${query.keyWord}%`)
      },
      order:{
        id:'DESC'
      },
      skip:(query.page-1)*query.pageSize,// 查询的索引从0开始 ,0代表第1页
      take:query.pageSize
    });

    const total = await this.user.count({
      where:{
        name:Like(`%${query.keyWord}%`)
      }
    });

    return {
      data,
      total
    }
  }

  async findOneById(id: number) {
    return await this.user.findOne({ where: { id } })
  }

  update(id: number, updateUserDto: UpdateUserDto) {
    return this.user.update(id,updateUserDto);
  }

  remove(id: number) {
    return this.user.delete(id);
  }
}